package com.mybatisplugin.springboot.conf.shiro;

import java.util.LinkedHashMap;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;

import com.mybatisplugin.springboot.conf.redis.RedisSessionDAO;

/**
 * shiro的配置类
 * @author Administrator
 *
 */
@Configuration
public class ShiroConfiguration {
	
	@SuppressWarnings("unused")
	private static Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
	
    @Bean(name="shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager securityManager) {
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        //配置登录的url和登录成功的url
        bean.setLoginUrl("/index/login");
        bean.setSuccessUrl("/home");
        //配置访问权限
        LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
        filterChainDefinitionMap.put("/jsp/login.jsp*", "anon"); //表示可以匿名访问
        filterChainDefinitionMap.put("/index/loginUser", "anon"); 
        filterChainDefinitionMap.put("/index/logout*","anon");
        filterChainDefinitionMap.put("/jsp/error.jsp*","anon");
        filterChainDefinitionMap.put("/jsp/index.jsp*","authc");
        filterChainDefinitionMap.put("/*", "authc");//表示需要认证才可以访问
        filterChainDefinitionMap.put("/**", "authc");//表示需要认证才可以访问
        filterChainDefinitionMap.put("/*.*", "authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }
    
    /**
     * ShiroDialect，为了在thymeleaf里使用shiro的标签的bean
     * @return
     */
    /*@Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }*/
    
    @Bean(name = "sessionValidationScheduler")
    public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() {
        ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
        scheduler.setInterval(900000);
        return scheduler;
    }
    
    @Bean(name="redisSessionDAO")
    public RedisSessionDAO redisSessionDAO(@Qualifier("ehCacheShiroManager") CacheManager cacheManager,@Qualifier("redisTemplate") RedisTemplate<String, Object> redisTemplate) {
    	RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    	redisSessionDAO.setCacheManager(cacheManager);
    	redisSessionDAO.setSessionIdGenerator(new JavaUuidSessionIdGenerator());
    	redisSessionDAO.setRedisTemplate(redisTemplate);
    	redisSessionDAO.setActiveSessionsCacheName("redisCacheShiroSession");
        return redisSessionDAO;
    }
    
    @Bean(name="sessionManager")
    public SessionManager sessionManager(@Qualifier("redisSessionDAO") SessionDAO sessionDAO,@Qualifier("sessionIdCookie") Cookie sessionIdCookie,@Qualifier("ehCacheShiroManager") CacheManager cacheManager) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setGlobalSessionTimeout(3600000);
        sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        sessionManager.setCacheManager(cacheManager);
        return sessionManager;
    }

    @Bean(name = "sessionIdCookie")
    public SimpleCookie getSessionIdCookie() {
        SimpleCookie cookie = new SimpleCookie("mysid");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(-1);
        return cookie;
    }
    
    /**
    * shiro缓存管理器;
    * 需要注入对应的其它的实体类中：
    * 1、安全管理器：securityManager
    * 可见securityManager是整个shiro的核心
    * @return
    */
    //配置核心安全事务管理器
    @Bean(name = "securityManager")
    public SecurityManager setSecurityManager(@Qualifier("sessionManager") SessionManager sessionManager,@Qualifier("authRealm") AuthRealm authRealm,@Qualifier("ehCacheShiroManager") CacheManager cacheManager) {
        System.err.println("--------------shiro已经加载----------------");
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        manager.setSessionManager(sessionManager);
        manager.setCacheManager(cacheManager);
        return manager;
    }
    
    //配置自定义的权限登录器
    @Bean(name="authRealm")
    public AuthRealm authRealm(@Qualifier("credentialsMatcher")CredentialsMatcher credentialsMatcher,@Qualifier("ehCacheShiroManager") CacheManager cacheManager) {
    	AuthRealm authRealm=new AuthRealm();
    	authRealm.setAuthenticationCachingEnabled(true);
    	authRealm.setAuthorizationCachingEnabled(true);
    	authRealm.setAuthenticationCacheName("authenticationCache");
    	authRealm.setAuthorizationCacheName("authorizationCache");
    	authRealm.setCachingEnabled(true);
    	authRealm.setCacheManager(cacheManager);
        authRealm.setCredentialsMatcher(credentialsMatcher);
        return authRealm;
    }
    
    //配置自定义的密码比较器
    @Bean(name="credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
        return new CredentialsMatcher();
    }
    
	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
	    return new LifecycleBeanPostProcessor();
	}
    
    @DependsOn("lifecycleBeanPostProcessor")
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
    
    /**
     * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持; Controller才能使用@RequiresPermissions
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(manager);
        return advisor;
    }
}